package com.seeingtv.common.utils.bean;

import net.sf.cglib.beans.BeanCopier;
import net.sf.cglib.core.Converter;

import java.util.Map;
import java.util.WeakHashMap;

/**
 * @author hubert
 * @date 2018/11/21
 * @description BeanCopyUtils
 */
public class BeanCopyUtils {
	/** 使用WeakHashMap缓存,在内存不足时会自动释放*/
	private final static Map<String,BeanCopier> BEAN_COPIER_MAP = new WeakHashMap<>();
	private final static Map<String,Converter> CONVERTER_MAP = new WeakHashMap<>();
	private static Object lock1 = new Object();
	private static Object lock2 = new Object();
	private BeanCopyUtils(){}
	/**
	 * 创建BeanCopier，并缓存
	 * @param src 源对象
	 * @param target 目标对象
	 * @param useConverter true or false
	 * @return BeanCopier
	 */
	private static BeanCopier getBeanCopier(Object src,Object target,boolean useConverter) {
		String key = generateKey(src,target,useConverter);
		BeanCopier bc = BEAN_COPIER_MAP.get(key);
		if (null == bc) {
			synchronized (lock1) {
				bc = BEAN_COPIER_MAP.get(key);
				if (null == bc) {
					bc = BeanCopier.create(src.getClass(),target.getClass(),useConverter);
					BEAN_COPIER_MAP.put(key,bc);
					System.out.println("Create BeanCopier with key:" + key);
				}
			}
		}
		return bc;
	}
	/**
	 * 复制对象属性
	 * @param src 源对象
	 * @param target 目标对象
	 */
	public static void copy(Object src,Object target) {
		BeanCopier bc = getBeanCopier(src, target, false);
		bc.copy(src,target,null);
	}
	/**
	 * 使用自定义的属性转换器复制对象属性
	 * @param src 源对象
	 * @param target 目标对象
	 * @param converter 转换器
	 */
	public static void copy(Object src,Object target,Converter converter) {
		BeanCopier bc = getBeanCopier(src,target,true);
		bc.copy(src,target,converter);
	}
	/**
	 * 对象属性复制，只复制fields中指定的属性，每个属性用逗号分隔
	 * @param src 源对象
	 * @param target 目标对象
	 * @param fields str
	 */
	public static void copyWithFields(Object src,Object target,final String fields) {
		BeanCopier bc = getBeanCopier(src,target,true);
		bc.copy(src, target, newConverter(src,target,fields,true));
	}
	/**
	 * 对象属性复制，排除指定属性
	 * @param src 源对象
	 * @param target 目标对象
	 * @param fields str
	 */
	public static void copyWithoutFields(Object src,Object target,final String fields) {
		BeanCopier bc = getBeanCopier(src,target,true);
		bc.copy(src, target, newConverter(src,target,fields,false));
	}
	/**
	 * new属性转换器，
	 * @param fields 需要复制或排除的属性
	 * @param fieldCopyFlag 属性复制标识 true:表明fields为需要复制的属性；false:表明fields是需要排除复制的属性
	 * @return Converter
	 */
	private static Converter newConverter(Object src,Object target,final String fields,final boolean fieldCopyFlag) {
		String key = buildConverterkey(src,target,fields,fieldCopyFlag);
		Converter converter = CONVERTER_MAP.get(key);
		if (null == converter) {
			synchronized (lock2) {
				converter = CONVERTER_MAP.get(key);
				if (null == converter) {
					converter = new Converter() {
						@Override
						public Object convert(Object fieldValue, Class fieldType, Object methodName) {
							// 得到属性名，如Name
							String field = methodName.toString().substring(3);
							// 将首字母小写
							field = field.substring(0,1).toLowerCase() + field.substring(1);
							boolean cond1 = fieldCopyFlag && fields.contains(field);
							boolean cond2 = !fieldCopyFlag && !fields.contains(field);
							if ( cond1 || cond2 ) {
								return fieldValue;
							}
							return null;
						}
					};
					CONVERTER_MAP.put(key,converter);
					System.out.println("Created Converter with key:" + key);
				}
			}
		}
		return converter;
	}
	private static String generateKey(Object src,Object target,boolean useConverter) {
		return src.getClass().getName() + target.getClass().getName() + String.valueOf(useConverter);
	}
	private static String buildConverterkey(Object src,Object target,String fields,boolean copyFlag) {
		String baseKey = generateKey(src,target,true);
		String key = baseKey + fields + String.valueOf(copyFlag);
		return key;
	}
}
